package ac.uk.icl.dell.vaadin.canvas.hezamu.canvas.client.ui;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gwt.canvas.client.Canvas;
import com.google.gwt.canvas.dom.client.CanvasGradient;
import com.google.gwt.canvas.dom.client.Context2d;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.ErrorEvent;
import com.google.gwt.event.dom.client.ErrorHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.VConsole;
import com.vaadin.client.communication.RpcProxy;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.PostLayoutListener;
import com.vaadin.client.ui.SimpleManagedLayout;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.Connect;
@Connect(ac.uk.icl.dell.vaadin.canvas.hezamu.canvas.Canvas.class)
public class CanvasConnector extends AbstractComponentConnector implements
SimpleManagedLayout, PostLayoutListener {
private static final long serialVersionUID = -2782526705807976265L;
private boolean needsDraw = false;
private final List<Command> commands;
private int lastXPosMove,lastYPosMove;
private MouseMoveHandler mouseMoveHandler;
private HandlerRegistration mouseMoveRegistration;
boolean mouseDown = false;
private boolean enableMouseSelectionMode = false;
private int mouseDownPoint_x,mouseDownPoint_y;
private final Map<String, CanvasGradient> gradients = new HashMap<String, CanvasGradient>();
private final CanvasServerRpc rpc = RpcProxy.create(CanvasServerRpc.class,
this);
private CanvasClientRpc clientRpc;
public CanvasConnector() {
commands = new ArrayList<Command>();
}
@Override
protected void init() {
super.init();
mouseMoveHandler = new MouseMoveHandler() {
@Override
public void onMouseMove(MouseMoveEvent event) {
int x = event.getClientX() - DOM.getAbsoluteLeft(getWidget().getElement());
int y = event.getClientY() - DOM.getAbsoluteTop(getWidget().getElement());
if(enableMouseSelectionMode){
if(mouseDown && ( (x-lastXPosMove >10 || x-lastXPosMove < -10) || ((y-lastYPosMove >10 || y-lastYPosMove < -10)))){
lastXPosMove=x;
lastYPosMove=y;
int x1,y1,width,height;
if(mouseDownPoint_x > x){
x1=x;
width=mouseDownPoint_x-x1;
}else{
x1=mouseDownPoint_x;
width=x-x1;
}
if(mouseDownPoint_y > y){
y1=y;
height=mouseDownPoint_y-y1;
}else{
y1=mouseDownPoint_y;
height=y-y1;
}
clientRpc.daveClear();
clientRpc.redraw();
clientRpc.saveContext();
clientRpc.setLineWidth(1d);
clientRpc.setStrokeStyle("#000");
clientRpc.strokeRect((double)x1, (double)y1, (double)width, (double)height, false);
clientRpc.restoreContext();
}
}
}
};
getWidget().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
MouseEventDetails med = MouseEventDetailsBuilder
.buildMouseEventDetails(event.getNativeEvent(),
getWidget().getElement());
rpc.clicked(med);
}
});
getWidget().addMouseDownHandler(new MouseDownHandler() {
@Override
public void onMouseDown(MouseDownEvent event) {
int x = event.getClientX() - DOM.getAbsoluteLeft(getWidget().getElement());
int y = event.getClientY() - DOM.getAbsoluteTop(getWidget().getElement());
if(enableMouseSelectionMode){
mouseDownPoint_x=x;
mouseDownPoint_y=y;
lastXPosMove=x;
lastYPosMove=y;
mouseDown=true;
//register new mouse move listener
mouseMoveRegistration = getWidget().addMouseMoveHandler(mouseMoveHandler);
}
rpc.mouseDown(x,y);
}
});
getWidget().addMouseUpHandler(new MouseUpHandler() {
@Override
public void onMouseUp(MouseUpEvent event) {
int x = event.getClientX() - DOM.getAbsoluteLeft(getWidget().getElement());
int y = event.getClientY() - DOM.getAbsoluteTop(getWidget().getElement());
if(enableMouseSelectionMode){
clientRpc.daveClear();
clientRpc.redraw();
if (mouseMoveRegistration != null) {
mouseMoveRegistration.removeHandler();
mouseMoveRegistration = null;
}
mouseDown=false;
//TODO
//cachedScrollTop=getWidget().getElement().getParentElement().getScrollTop();
//cachedScrollLeft=getWidget().getElement().getParentElement().getScrollLeft();
}
rpc.mouseUp(x, y);
}
});
clientRpc = new CanvasClientRpc() {
private static final long serialVersionUID = -7521521510799765779L;
private final Context2d ctx = getWidget().getContext2d();
@Override
public void fillRect(final Double startX, final Double startY,
final Double width, final Double height) {
runCommand(new Command() {
@Override
public void execute() {
ctx.fillRect(startX, startY, width, height);
}
});
}
@Override
public void drawImage1(final String url, final Double offsetX,
final Double offsetY) {
runCommand(new Command() {
@Override
public void execute() {
VConsole.log("Drawing " + url + "\n at " + offsetX
+ "," + offsetY);
ctx.drawImage(
ImageElement.as(new Image(url).getElement()),
offsetX, offsetY);
VConsole.log("Drawing complete");
}
});
}
@Override
public void drawImage2(final String url, final Double offsetX,
final Double offsetY, final Double imageWidth,
final Double imageHeight) {
runCommand(new Command() {
@Override
public void execute() {
VConsole.log("Drawing " + url + "\n at " + offsetX
+ "," + offsetY + " w" + imageWidth + " h"
+ imageHeight);
ctx.drawImage(
ImageElement.as(new Image(url).getElement()),
offsetX, offsetY, imageWidth, imageHeight);
VConsole.log("Drawing complete");
}
});
}
@Override
public void drawImage3(final String url, final Double sourceX,
final Double sourceY, final Double sourceWidth,
final Double sourceHeight, final Double destX,
final Double destY, final Double destWidth,
final Double destHeight) {
runCommand(new Command() {
@Override
public void execute() {
VConsole.log("Drawing " + url + "\n from " + sourceX
+ "," + sourceY + " w" + sourceWidth + " h"
+ sourceHeight + " to " + destX + "," + destY
+ " " + destWidth + "x" + destHeight);
ctx.drawImage(
ImageElement.as(new Image(url).getElement()),
sourceX, sourceY, sourceWidth, sourceHeight,
destX, destY, destWidth, destHeight);
VConsole.log("Drawing complete");
}
});
}
@Override
public void fill() {
runCommand(new Command() {
@Override
public void execute() {
ctx.fill();
}
});
}
@Override
public void fillText(final String text, final Double x,
final Double y, final Double maxWidth) {
runCommand(new Command() {
@Override
public void execute() {
ctx.fillText(text, x, y, maxWidth);
}
});
}
@Override
public void setFont(final String font) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setFont(font);
}
});
}
@Override
public void setTextBaseline(final String textBaseline) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setTextBaseline(textBaseline);
}
});
}
@Override
public void lineTo(final Double x, final Double y) {
runCommand(new Command() {
@Override
public void execute() {
ctx.lineTo(x, y);
}
});
}
@Override
public void moveTo(final Double x, final Double y) {
runCommand(new Command() {
@Override
public void execute() {
ctx.moveTo(x, y);
}
});
}
@Override
public void quadraticCurveTo(final Double cpx, final Double cpy,
final Double x, final Double y) {
runCommand(new Command() {
@Override
public void execute() {
ctx.quadraticCurveTo(cpx, cpy, x, y);
}
});
}
@Override
public void rect(final Double startX, final Double startY,
final Double rectWidth, final Double rectHeight) {
runCommand(new Command() {
@Override
public void execute() {
ctx.rect(startX, startY, rectWidth, rectHeight);
}
});
}
@Override
public void rotate(final Double angle) {
runCommand(new Command() {
@Override
public void execute() {
ctx.rotate(angle);
}
});
}
@Override
public void setFillStyle(final String color) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setFillStyle(color);
}
});
}
@Override
public void setLineCap(final String lineCap) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setLineCap(lineCap);
}
});
}
@Override
public void setLineJoin(final String lineJoin) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setLineJoin(lineJoin);
}
});
}
@Override
public void setLineWidth(final Double lineWidth) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setLineWidth(lineWidth);
}
});
}
@Override
public void setMiterLimit(final Double miterLimit) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setMiterLimit(miterLimit);
}
});
}
@Override
public void strokeRect(final Double startX, final Double startY,
final Double strokeWidth, final Double strokeHeight) {
runCommand(new Command() {
@Override
public void execute() {
ctx.strokeRect(startX, startY, strokeWidth,
strokeHeight);
}
});
}
@Override
public void transform(final Double m11, final Double m12,
final Double m21, final Double m22, final Double dx,
final Double dy) {
runCommand(new Command() {
@Override
public void execute() {
ctx.transform(m11, m12, m21, m22, dx, dy);
}
});
}
@Override
public void arc(final Double x, final Double y,
final Double radius, final Double startAngle,
final Double endAngle, Boolean antiClockwise) {
runCommand(new Command() {
@Override
public void execute() {
ctx.arc(x, y, radius, startAngle, endAngle);
}
});
}
@Override
public void translate(final Double x, final Double y) {
runCommand(new Command() {
@Override
public void execute() {
ctx.translate(x, y);
}
});
}
@Override
public void scale(final Double x, final Double y) {
runCommand(new Command() {
@Override
public void execute() {
ctx.scale(x, y);
}
});
}
@Override
public void stroke() {
runCommand(new Command() {
@Override
public void execute() {
ctx.stroke();
}
});
}
@Override
public void saveContext() {
runCommand(new Command() {
@Override
public void execute() {
ctx.save();
}
});
}
@Override
public void restoreContext() {
runCommand(new Command() {
@Override
public void execute() {
ctx.restore();
}
});
}
@Override
public void setStrokeStyle(final String rgb) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setStrokeStyle(rgb);
}
});
}
@Override
public void beginPath() {
runCommand(new Command() {
@Override
public void execute() {
ctx.beginPath();
}
});
}
@Override
public void clear() {
ctx.clearRect(0, 0, getWidget().getCoordinateSpaceWidth(),
getWidget().getCoordinateSpaceHeight());
clearCommands();
}
@Override
public void setGlobalAlpha(final Double alpha) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setGlobalAlpha(alpha);
}
});
}
@Override
public void closePath() {
runCommand(new Command() {
@Override
public void execute() {
ctx.closePath();
}
});
}
@Override
public void setGlobalCompositeOperation(final String mode) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setGlobalCompositeOperation(mode);
}
});
}
@Override
public void setGradientFillStyle(final String gradientName) {
runCommand(new Command() {
@Override
public void execute() {
if (gradients.containsKey(gradientName)) {
ctx.setFillStyle(gradients.get(gradientName));
} else {
System.err
.println("setGradientFillStyle: Gradient not foud with name "
+ gradientName);
}
}
});
}
@Override
public void createLinearGradient(final String name,
final Double x0, final Double y0, final Double x1,
final Double y1) {
runCommand(new Command() {
@Override
public void execute() {
CanvasGradient newGradient = ctx.createLinearGradient(
x0, y0, x1, y1);
gradients.put(name, newGradient);
}
});
}
@Override
public void createRadialGradient(final String name,
final Double x0, final Double y0, final Double r0,
final Double x1, final Double y1, final Double r1) {
runCommand(new Command() {
@Override
public void execute() {
CanvasGradient newGradient = ctx.createRadialGradient(
x0, y0, r0, x1, y1, r1);
gradients.put(name, newGradient);
}
});
}
@Override
public void setGradientStrokeStyle(final String gradientName) {
runCommand(new Command() {
@Override
public void execute() {
if (gradients.containsKey(gradientName)) {
ctx.setStrokeStyle(gradients.get(gradientName));
} else {
System.err
.println("setGradientStrokeStyle: Gradient not found with name "
+ gradientName);
}
}
});
}
@Override
public void addColorStop(final String gradientName,
final Double offset, final String color) {
runCommand(new Command() {
@Override
public void execute() {
if (gradients.containsKey(gradientName)) {
gradients.get(gradientName).addColorStop(offset,
color);
} else {
System.err
.println("addColorStop: Gradient not foud with name "
+ gradientName);
}
}
});
}
@Override
public void loadImages(final String[] urls) {
final List<String> imagesToLoad = new ArrayList<String>();
imagesToLoad.addAll(Arrays.asList(urls));
for (final String url : urls) {
final Image image = new Image(url);
image.addLoadHandler(new LoadHandler() {
@Override
public void onLoad(LoadEvent event) {
RootPanel.get().remove(image);
imagesToLoad.remove(url);
if (imagesToLoad.isEmpty())
rpc.imagesLoaded();
}
});
image.addErrorHandler(new ErrorHandler() {
@Override
public void onError(ErrorEvent event) {
RootPanel.get().remove(image);
imagesToLoad.remove(url);
if (imagesToLoad.isEmpty())
rpc.imagesLoaded();
}
});
// Force loading of the image
image.setVisible(false);
RootPanel.get().add(image);
}
}
@Override
public void setBackgroundColor(final String color) {
runCommand(new Command() {
@Override
public void execute() {
DOM.setStyleAttribute(getWidget().getElement(),"backgroundColor", color);
}
});
}
@Override
public void redraw() {
for (Command command :commands) {
command.execute();
}
}
@Override
public void daveClear(){
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, getWidget().getCoordinateSpaceWidth(), getWidget().getCoordinateSpaceHeight());
}
@Override
public void strokeRect(Double startX, Double startY,
Double strokeWidth, Double strokeHeight,
boolean saveInCommands) {
ctx.strokeRect(startX, startY, strokeWidth,
strokeHeight);
}
@Override
public void enableMouseSelectionRectangle(boolean enable) {
enableMouseSelectionMode = enable;
}
@Override
public void bezierCurveTo(final Double cp1x, final Double cp1y, final Double cp2x,
final Double cp2y, final Double x, final Double y) {
runCommand(new Command() {
@Override
public void execute() {
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
}
});
}
@Override
public void textAlign(final String textAlign) {
runCommand(new Command() {
@Override
public void execute() {
ctx.setTextAlign(textAlign);
}
});
}
@Override
public void fillText(final String text, final double x, final double y) {
runCommand(new Command() {
@Override
public void execute() {
ctx.fillText(text, x, y);
}
});
}
@Override
public void setMinimumSize(int width, int height) {
if (width > getWidget().getCoordinateSpaceWidth())
{
getWidget().setWidth(width + "px");
}
if (height > getWidget().getCoordinateSpaceHeight())
{
getWidget().setHeight(height + "px");
}
}
};
registerRpc(CanvasClientRpc.class, clientRpc);
}
@Override
protected Widget createWidget() {
return Canvas.createIfSupported();
}
@Override
public Canvas getWidget() {
return (Canvas) super.getWidget();
}
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
}
@Override
public void layout() {
int newHt = getWidget().getElement().getOffsetHeight();
if (newHt != getWidget().getCoordinateSpaceHeight()) {
getWidget().setCoordinateSpaceHeight(newHt);
needsDraw = true;
}
int newWt = getWidget().getElement().getOffsetWidth();
if (newWt != getWidget().getCoordinateSpaceWidth()) {
getWidget().setCoordinateSpaceWidth(newWt);
needsDraw = true;
}
}
@Override
public void postLayout() {
if (needsDraw) {
for (Command cmd : commands)
cmd.execute();
needsDraw = false;
}
}
public void runCommand(Command command) {
if (commands.add(command))
command.execute();
}
public void clearCommands() {
commands.clear();
}
}